package externalSort.Tournament;

import externalSort.filePair;

import java.io.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class writingTask implements Runnable{

    private BufferedWriter bw;

    private final Lock lock;
    private final Lock bufferLock;
    private final Semaphore toReading;
    private final Semaphore toWriting;

    public String fileName;
    public int currentGenerations;

    private int lastWrittenValue = Integer.MIN_VALUE;
    private int fileCnt;

    public List<filePair> fileNames;
    public List<bufferSimulator> buffers;

    private final int bufferSize;
    private boolean allFinished;

    public writingTask(List<bufferSimulator> buffers,
                       Semaphore toReading,Semaphore toWriting,Lock lock,
                       int bufferSize,List<filePair> fileNames) throws IOException {
//        System.out.println("=== [writingTask] 初始化开始 ===");
        this.currentGenerations = 0; // 添加初始化
        this.fileName = "./file/generation/run_" + currentGenerations + ".txt";
        File file = new File(fileName);
        boolean ret = file.getParentFile().mkdirs(); // 创建目录
//        System.out.println("[writingTask] 创建初始文件: " + fileName + ", 目录创建: " + ret);
        this.bw = new BufferedWriter(new FileWriter(file), bufferSize);

        this.fileNames=fileNames;
        this.bufferLock=lock;
        this.lock=new ReentrantLock();
        this.toReading=toReading;
        this.toWriting=toWriting;

        this.bufferSize=bufferSize;
        this.buffers=buffers;
        allFinished=false;
//        System.out.println("=== [writingTask] 初始化完成 ===");
    }

    @Override
    public void run(){
//        System.out.println("=== [writingTask] 写入线程开始运行 ===");
        try {
            int writeCycle = 0;
            while(!isAllFinished()) {
                writeCycle++;
//                System.out.println("[writingTask] 循环 " + writeCycle + " - 尝试获取toWriting, 当前可用: " + toWriting.availablePermits());
                toWriting.acquire();
//                System.out.println("[writingTask] 成功获取toWriting");

                bufferSimulator cur = null;
                bufferLock.lock();
//                System.out.println("[writingTask] 获取bufferLock，检查缓冲区状态:");

                for(bufferSimulator buffer:buffers){
//                    System.out.println("[writingTask] 缓冲区状态: " + buffer.getState() + "，大小: " + buffer.size());
                    if(buffer.getState()==BufferState.FULL){
                        cur=buffer;
//                        System.out.println("[writingTask] 找到FULL缓冲区，大小: " + cur.size());
                        break;
                    }
                }
//                System.out.print("\n");

                if (cur != null) {
//                    System.out.println("[writingTask] 设置缓冲区状态为WRITING");
                    cur.setState(BufferState.WRITING);
                    bufferLock.unlock();
//                    System.out.println("[writingTask] 释放bufferLock，准备写入文件");

                    writeBufferToFile(cur);

                    bufferLock.lock();
//                    System.out.println("[writingTask] 获取bufferLock，设置缓冲区状态为IDLE");
                    cur.setState(BufferState.IDLE);
//                    System.out.println("[writingTask] 释放toIdle，当前可用: " + toReading.availablePermits());
                    toReading.release();
                    bufferLock.unlock();
//                    System.out.println("[writingTask] 释放bufferLock");
                }else{
//                    System.out.println("(Error)[writingTask]: 未从list中找出FULL的buffer");
                    bufferLock.unlock();
                }

//                System.out.println("[writingTask] 当前allFinished=" + isAllFinished());
            }

//            System.out.print("\n");
//            System.out.println("=== [writingTask] 写入线程运行结束 ===");
        } catch (Exception e) {
            System.out.println("(ERROR)[writingTask] 发生异常: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private void writeBufferToFile(bufferSimulator buffer) throws IOException, InterruptedException {
//        System.out.println("[writeBufferToFile] 开始写入缓冲区数据，缓冲区大小: " + buffer.size());
        try{
            lock.lock();
//            System.out.println("[writeBufferToFile] 获取写入锁");

            // 在写入前检查并创建文件写入器
//            ensureWriterOpen();
            boolean shouldFinished=false;
            int writeCount = 0;

            while (!buffer.isEmpty()) {
                int cur = buffer.poll();
//                System.out.println("[writeBufferToFile] 从缓冲区取出值: " + cur + "，剩余大小: " + buffer.size());

                if(cur==Integer.MAX_VALUE){
//                    System.out.println("[writeBufferToFile] 检测到结束信号(Integer.MAX_VALUE)");
                    shouldFinished=true;
                    break;
                }
                if(cur==Integer.MIN_VALUE){
//                    System.out.println("[writeBufferToFile] 跳过MIN_VALUE");
                    continue;
                }

                // 检查是否需要切换文件
                if (cur < lastWrittenValue) {
//                    System.out.println("[writeBufferToFile] 检测到顺串结束: " + cur + " < " + lastWrittenValue + "，切换文件");
                    // 先刷新当前文件
                    bw.flush();
                    // 然后切换文件
                    switchFileName();
                }

                lastWrittenValue = cur;
                bw.write(cur + "\n");
                this.fileCnt++;
//                writeCount++;

//                if (writeCount % 10 == 0) { // 每10个值打印一次进度
//                    System.out.println("[writeBufferToFile] 已写入 " + writeCount + " 个值，当前文件计数: " + fileCnt);
//                }
            }

            // 写入完成后刷新
            bw.flush();
//            System.out.println("[writeBufferToFile] 写入完成，共写入 " + writeCount + " 个值，当前文件总数: " + fileCnt);

            if(shouldFinished){
//                System.out.println("[writeBufferToFile] 检测到结束信号，准备关闭写入器");
                flushAndClose();
            }
        } finally {
            lock.unlock();
//            System.out.println("[writeBufferToFile] 释放写入锁");
        }
    }

    /**
     * 切换文件（新顺串开始）
     * 当检测到当前值小于上一个值时，表示新顺串开始
     */
    private void switchFileName() {
        try {
            this.lock.lock();
//            System.out.println("[switchFileName] 开始切换文件，当前文件: " + fileName + "，写入数量: " + fileCnt);

            // 先把之前的写进去
            this.fileNames.add(new filePair(this.fileName,fileCnt));
//            System.out.println("[switchFileName] 添加文件记录: " + fileName + "，数量: " + fileCnt);

            currentGenerations++;
            String newFileName = "./file/generation/run_" + currentGenerations + ".txt";
//            System.out.println("[switchFileName] 新文件名: " + newFileName);

            // 关闭旧文件
            if (bw != null) {
                bw.close();
//                System.out.println("[switchFileName] 关闭旧文件");
            }

            // 创建新文件
            File file = new File(newFileName);
            boolean ret = file.getParentFile().mkdirs();
            this.bw = new BufferedWriter(new FileWriter(file), bufferSize);
            this.fileName = newFileName;
            this.fileCnt=0;
//            System.out.println("[switchFileName] 创建新文件完成，重置计数器");
            this.lock.unlock();
        } catch (IOException e) {
//            System.out.println("[externalSort.Tournament.writingTask]: IOException occur " + e.getMessage());
        }
    }

    /**
     * 刷新并关闭写入器，处理剩余数据
     */
    public void flushAndClose() throws InterruptedException {
        System.out.println("[flushAndClose] 开始刷新并关闭写入器");
        lock.lock();
        try {
//            System.out.println("[flushAndClose] 获取写入锁");

            // 写入剩余数据
            this.fileNames.add(new filePair(this.fileName,fileCnt));
//            System.out.println("[flushAndClose] 添加最终文件记录: " + fileName + "，数量: " + fileCnt);

            this.allFinished=true;
//            System.out.println("[flushAndClose] 设置allFinished=true");

            try {
                if (bw != null) {
                    bw.close();
//                    System.out.println("[flushAndClose] 成功关闭BufferedWriter");
                }
            } catch (IOException e) {
//                System.out.println("[externalSort.Tournament.writingTask]: IOException during close " + e.getMessage());
            }

        } finally {
            lock.unlock();
//            System.out.println("[flushAndClose] 释放写入锁");
        }
    }

//    private void ensureWriterOpen() throws IOException {
//        if (bw == null) {
//            System.out.println("[ensureWriterOpen] 检测到bw为null，重新创建写入器");
//            this.fileName = "./file/generation/run_" + currentGenerations + ".txt";
//            File file = new File(fileName);
//            boolean ret=file.getParentFile().mkdirs();
//            this.bw = new BufferedWriter(new FileWriter(file), bufferSize);
//            System.out.println("[ensureWriterOpen] 创建写入器: " + fileName);
//        } else {
//            System.out.println("[ensureWriterOpen] 写入器已打开: " + fileName);
//        }
//    }

    public boolean isAllFinished() {
        lock.lock();
        try {
            boolean result = this.allFinished;
//            System.out.println("[isAllFinished] 检查完成状态: " + result);
            return result;
        } finally {
            lock.unlock();
        }
    }
}